package com.zzedu.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.zzedu.common.enums.CommonEnums;
import com.zzedu.common.utils.StringUtils;
import com.zzedu.common.utils.bean.BeanUtils;
import com.zzedu.domain.OrderSumRenewVO;
import com.zzedu.domain.ZzSchool;
import com.zzedu.domain.ZzStuRenewOrder;
import com.zzedu.domain.ZzStudent;
import com.zzedu.dto.OrderSumDTO;
import com.zzedu.dto.ZzStuRenewOrderDTO;
import com.zzedu.mapper.ZzStuRenewOrderMapper;
import com.zzedu.mapper.ZzStudentMapper;
import com.zzedu.service.IZzExerciseBookService;
import com.zzedu.service.IZzSchoolService;
import com.zzedu.service.IZzStuRenewOrderService;
import com.zzedu.system.service.ISysUserService;
import com.zzedu.vo.ZzStuRenewOrderVO;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * (教育-学生)学生续费订单Service业务层处理
 *
 * @author Mr.Wang
 * @date 2025-08-16
 */
@Service
public class ZzStuRenewOrderServiceImpl extends ServiceImpl<ZzStuRenewOrderMapper, ZzStuRenewOrder> implements IZzStuRenewOrderService {


    @Autowired
    private IZzSchoolService zzSchoolService;

    @Autowired
    private ZzStudentMapper zzStudentMapper;

    @Autowired
    private ISysUserService sysUserService;

    @Autowired
    private IZzExerciseBookService zzExerciseBookService;

    @Override
    public LambdaQueryWrapper<ZzStuRenewOrder> buildQuery(ZzStuRenewOrderDTO zzStuRenewOrder) {
        LambdaQueryWrapper<ZzStuRenewOrder> lambdaQueryWrapper = Wrappers.lambdaQuery();
        lambdaQueryWrapper.eq(null != zzStuRenewOrder.getStuId(), ZzStuRenewOrder::getStuId, zzStuRenewOrder.getStuId());
        lambdaQueryWrapper.eq(null != zzStuRenewOrder.getOrderType(), ZzStuRenewOrder::getOrderType, zzStuRenewOrder.getOrderType());
        lambdaQueryWrapper.eq(null != zzStuRenewOrder.getRenewType(), ZzStuRenewOrder::getRenewType, zzStuRenewOrder.getRenewType());
        lambdaQueryWrapper.eq(null != zzStuRenewOrder.getFeeType(), ZzStuRenewOrder::getFeeType, zzStuRenewOrder.getFeeType());
        lambdaQueryWrapper.eq(null != zzStuRenewOrder.getPayState(), ZzStuRenewOrder::getPayState, zzStuRenewOrder.getPayState());
        lambdaQueryWrapper.eq(null != zzStuRenewOrder.getValidFlag(), ZzStuRenewOrder::getValidFlag, zzStuRenewOrder.getValidFlag());
        lambdaQueryWrapper.eq(null != zzStuRenewOrder.getPayChargeId(), ZzStuRenewOrder::getPayChargeId, zzStuRenewOrder.getPayChargeId());
        lambdaQueryWrapper.exists(StringUtils.isNotBlank(zzStuRenewOrder.getStuName()), " (select 1 from zz_student c where c.id=zz_stu_renew_order.stu_id and  c.deleted=0 and c.stu_name like concat('%', {0}, '%'))", zzStuRenewOrder.getStuName());
        lambdaQueryWrapper.exists(StringUtils.isNotBlank(zzStuRenewOrder.getStuTel()), " (select 1 from zz_student c where c.id=zz_stu_renew_order.stu_id and  c.deleted=0 and c.tel like concat('%', {0}, '%'))", zzStuRenewOrder.getStuTel());
        lambdaQueryWrapper.exists(" (select 1 from zz_student c where c.id=zz_stu_renew_order.stu_id and  c.deleted=0)");
        if (null != zzStuRenewOrder.getSchoolIdArray()) {
            lambdaQueryWrapper.in(ZzStuRenewOrder::getSchoolId, zzStuRenewOrder.getSchoolIdArray());
        }
        if (null != zzStuRenewOrder.getStartTime()) {
            lambdaQueryWrapper.ge(ZzStuRenewOrder::getGmtCreate, zzStuRenewOrder.getStartTime());
        }
        if (null != zzStuRenewOrder.getEndTime()) {
            lambdaQueryWrapper.le(ZzStuRenewOrder::getGmtCreate, zzStuRenewOrder.getEndTime());
        }
        lambdaQueryWrapper.orderByDesc(ZzStuRenewOrder::getId);
        return lambdaQueryWrapper;
    }

    @Override
    public List<ZzStuRenewOrderVO> convertVO(List<ZzStuRenewOrder> zzStuRenewOrderList) {
        List<ZzStuRenewOrderVO> zzStuRenewOrderVOList = Lists.newArrayList();
        if (CollectionUtils.isNotEmpty(zzStuRenewOrderList)) {
            List<Long> stuIdList = zzStuRenewOrderList.stream().map(ZzStuRenewOrder::getStuId).distinct().collect(Collectors.toList());
            List<Long> schoolIdList = zzStuRenewOrderList.stream().map(ZzStuRenewOrder::getSchoolId).distinct().collect(Collectors.toList());
            List<Long> userIdList = zzStuRenewOrderList.stream().map(ZzStuRenewOrder::getCreateBy).distinct().collect(Collectors.toList());
            userIdList.add(-100L);
            List<ZzStudent> zzStudentList = this.zzStudentMapper.selectByIds(stuIdList);
            List<ZzSchool> zzSchoolList = this.zzSchoolService.listByIds(schoolIdList);
            Map<Long, ZzSchool> schoolIdAndName = zzSchoolList.stream().collect(Collectors.toMap(ZzSchool::getId, Function.identity()));
            Map<Long, ZzStudent> stuIdAndName = zzStudentList.stream().collect(Collectors.toMap(ZzStudent::getId, Function.identity()));
            for (ZzStuRenewOrder zzStuRenewOrder : zzStuRenewOrderList) {
                ZzStuRenewOrderVO zzStuRenewOrderVO = new ZzStuRenewOrderVO();
                BeanUtils.copyBeanProp(zzStuRenewOrderVO, zzStuRenewOrder);
                ZzSchool zzSchool = schoolIdAndName.get(zzStuRenewOrder.getSchoolId());
                if (null != zzSchool) {
                    zzStuRenewOrderVO.setSchoolName(zzSchool.getSchoolName());
                    zzStuRenewOrderVO.setContacts(zzSchool.getContacts());
                    zzStuRenewOrderVO.setStuNum(zzSchool.getStudentCapacity());
                    zzStuRenewOrderVO.setTel(zzSchool.getTel());
                }
                ZzStudent zzStudent = stuIdAndName.get(zzStuRenewOrder.getStuId());
                if (null != zzStudent) {
                    zzStuRenewOrderVO.setStuName(zzStudent.getStuName());
                }

                zzStuRenewOrderVOList.add(zzStuRenewOrderVO);
            }
        }
        return zzStuRenewOrderVOList;
    }

    public void addOrder(Long id, Integer memberType, Integer orderType, ZzStudent zzStudent, ZzSchool zzSchool, LocalDateTime end, LocalDateTime now, boolean isExpire) {
        ZzStuRenewOrder zzStuRenewOrder = new ZzStuRenewOrder();
        zzStuRenewOrder.setRenewType(zzStudent.getMemberType());
        zzStuRenewOrder.setSchoolId(zzSchool.getId());
        zzStuRenewOrder.setFeeType(zzSchool.getFeeType());
        zzStuRenewOrder.setOrderType(orderType);
        zzStuRenewOrder.setExpireDate(end);
        zzStuRenewOrder.setStartDate(now);
        zzStuRenewOrder.setStuId(id);
        zzStuRenewOrder.setPayState(CommonEnums.NO.getCode());
        if (isExpire) {
            //直接生效
            zzStuRenewOrder.setValidFlag(2);
        } else {
            //待生效
            zzStuRenewOrder.setValidFlag(1);
        }
        BigDecimal referencePrice = zzSchool.getReferencePrice();
        Integer feeType = zzSchool.getFeeType();
        BigDecimal feeRatio = zzSchool.getRatio();
        Assert.notNull(referencePrice, "年参考价不存在");
        Assert.notNull(feeType, "佣金方式不存在");
        Assert.notNull(feeRatio, "佣金、佣金比例方式不存在");
        BigDecimal fee = BigDecimal.ZERO;
        // 1-比例 2-固定金额
        if (1 == feeType) {
            //1个季度 * 续费季度(memberType)
            fee = referencePrice.multiply(feeRatio).divide(new BigDecimal("400"), 2, RoundingMode.HALF_UP).multiply(new BigDecimal(String.valueOf(memberType)));
        } else if (2 == feeType) {
            fee = feeRatio.divide(new BigDecimal("4"), 2, RoundingMode.HALF_UP).multiply(new BigDecimal(String.valueOf(memberType)));
        }
        zzStuRenewOrder.setOrderAmount(fee);
        this.save(zzStuRenewOrder);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int abandonment(List<Long> ids) {
        List<ZzStuRenewOrder> zzStuRenewOrderList = this.list(Wrappers.lambdaQuery(ZzStuRenewOrder.class)
                .in(ZzStuRenewOrder::getValidFlag, Lists.newArrayList(1, 2))
                .in(ZzStuRenewOrder::getId, ids)
                .eq(ZzStuRenewOrder::getPayState, CommonEnums.NO.getCode())
                .orderByAsc(ZzStuRenewOrder::getId)
        );
        if (CollectionUtils.isNotEmpty(zzStuRenewOrderList)) {
            Map<Integer, Long> daysMap = Maps.newHashMap();
            daysMap.put(1, 92L);
            daysMap.put(2, 183L);
            daysMap.put(3, 275L);
            daysMap.put(4, 366L);
            for (ZzStuRenewOrder zzStuRenewOrder : zzStuRenewOrderList) {
                //查询当前学生多有的续费订单
                //最近的废弃那条
                ZzStuRenewOrder preZzStuRenewOrder = this.getOne(
                        Wrappers.lambdaQuery(ZzStuRenewOrder.class)
                                .eq(ZzStuRenewOrder::getStuId, zzStuRenewOrder.getStuId())
                                .lt(ZzStuRenewOrder::getId, zzStuRenewOrder.getId())
                                .orderByDesc(ZzStuRenewOrder::getId)
                                .last("limit 1")
                );
                int validFlag = zzStuRenewOrder.getValidFlag();
                LocalDateTime startDate = null;
                if (null == preZzStuRenewOrder) {
                    //是第一条
                    startDate = zzStuRenewOrder.getStartDate().plusDays(-1L);
                } else {
                    //当前这条
                    startDate = LocalDateTime.of(preZzStuRenewOrder.getExpireDate().toLocalDate(), LocalTime.of(00, 00, 00));
                }
                //重新计算后续订单都时间
                List<ZzStuRenewOrder> zzStuRenewOrders = this.list(
                        Wrappers.lambdaQuery(ZzStuRenewOrder.class)
                                .eq(ZzStuRenewOrder::getStuId, zzStuRenewOrder.getStuId())
                                .gt(ZzStuRenewOrder::getId, zzStuRenewOrder.getId())
                                .orderByAsc(ZzStuRenewOrder::getId)
                );
                ZzStudent zzStudent = this.zzStudentMapper.selectById(zzStuRenewOrder.getStuId());
                LocalDateTime expireAt = null;
                if (CollectionUtils.isNotEmpty(zzStuRenewOrders)) {
                    for (ZzStuRenewOrder historyOrder : zzStuRenewOrders) {
                        startDate = LocalDateTime.of(startDate.toLocalDate().plusDays(1), LocalTime.of(00, 00, 00));
                        historyOrder.setStartDate(startDate);
                        startDate = startDate.plusDays(daysMap.get(historyOrder.getRenewType()));
                        startDate = LocalDateTime.of(startDate.toLocalDate(), LocalTime.of(23, 59, 59));
                        historyOrder.setExpireDate(startDate);
                        if (2 == validFlag && null == expireAt) {
                            historyOrder.setValidFlag(2);
                        }
                        this.updateById(historyOrder);
                        zzStudent.setValidTo(startDate);
                        if (null == expireAt) {
                            expireAt = startDate;
                        }
                    }
                }
                if (2 == validFlag) {
                    //有效期更改
                    zzStudent.setMemberType(zzStuRenewOrder.getRenewType());
                    zzStudent.setExpireAt(expireAt);
                }
                zzStuRenewOrder.setValidFlag(4);
                this.updateById(zzStuRenewOrder);
                this.zzStudentMapper.updateById(zzStudent);
            }
        }
        return 1;
    }

    public IPage<OrderSumRenewVO> orderSumList(OrderSumDTO query) {
        return baseMapper.orderSumList(query.getPageDTO(), query);
    }


    public IPage<OrderSumRenewVO> orderSumListPayOrder(OrderSumDTO query) {
        return baseMapper.orderSumListPayOrder(query.getPageDTO(), query);
    }

    public IPage<OrderSumRenewVO> orderSumListPayOrderToMonth(OrderSumDTO query) {
        return baseMapper.orderSumListPayOrderToMonth(query.getPageDTO(), query);
    }
}